﻿using System;
using System.Collections;
using System.Web;
using System.IO;
using System.Drawing;
using System.Net;
using System.Configuration;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Collections.Specialized;
using System.Text;
using java.security;
using Newtonsoft.Json;
using java.lang;
using Exception = System.Exception;

namespace Common
{
    public class UpLoad
    {
        int imgmaxheight = 1024;
        /// <summary>
        /// 通过文件流上传文件方法
        /// </summary>
        /// <param name="byteData">文件字节数组</param>
        /// <param name="fileName">文件名</param>
        /// <param name="isThumbnail">是否生成缩略图</param>
        /// <param name="isWater">是否打水印</param>
        /// <returns>上传成功返回JSON字符串</returns>
        public string FileSaveAs(byte[] byteData, string fileName, bool isThumbnail, bool isWater)
        {
            try
            {
                string fileExt = Path.GetExtension(fileName).Trim('.'); //文件扩展名，不含“.”
                string newFileName = Utils.GetRamCode() + "." + fileExt; //随机生成新的文件名
                string newThumbnailFileName = "thumb_" + newFileName; //随机生成缩略图文件名

                string upLoadPath = GetUpLoadPath(); //本地上传目录相对路径
                string fullUpLoadPath = Utils.GetMapPath(upLoadPath); //本地上传目录的物理路径
                string newFilePath = upLoadPath + newFileName; //本地上传后的路径
                string newThumbnailPath = upLoadPath + newThumbnailFileName; //本地上传后的缩略图路径

                byte[] thumbData = null; //缩略图文件流

                //检查文件字节数组是否为NULL
                if (byteData == null)
                {
                    return "{\"status\": 0, \"msg\": \"请选择要上传的文件！\"}";
                }
                //检查文件扩展名是否合法
                if (!CheckFileExt(fileExt))
                {
                    return "{\"status\": 0, \"msg\": \"不允许上传" + fileExt + "类型的文件！\"}";
                }
                //检查文件大小是否合法
                if (!CheckFileSize(fileExt, byteData.Length))
                {
                    return "{\"status\": 0, \"msg\": \"文件超过限制的大小！\"}";
                }
                //如果是图片，检查是否需要生成缩略图，是则裁剪生成300*300长度
                if (IsImage(fileExt) && isThumbnail)
                {
                    thumbData = Thumbnail.MakeThumbnailImage(byteData, fileExt, 300, 300, "Cut");
                }
                else
                {
                    newThumbnailPath = newFilePath; //不生成缩略图则返回原图
                }
                //检查本地上传的物理路径是否存在，不存在则创建
                if (!Directory.Exists(fullUpLoadPath))
                {
                    Directory.CreateDirectory(fullUpLoadPath);
                }
                //保存主文件
                FileHelper.SaveFile(byteData, fullUpLoadPath + newFileName);
                //保存缩略图文件
                if (thumbData != null)
                {
                    FileHelper.SaveFile(thumbData, fullUpLoadPath + newThumbnailFileName);
                }
                //处理完毕，返回JOSN格式的文件信息
                return "{\"status\": 1, \"msg\": \"上传文件成功！\", \"name\": \""
                    + fileName + "\", \"path\": \"" + newFilePath + "\", \"thumb\": \""
                    + newThumbnailPath + "\", \"size\": " + byteData.Length + ", \"ext\": \"" + fileExt + "\"}";
            }
            catch
            {
                return "{\"status\": 0, \"msg\": \"上传过程中发生意外错误！\"}";
            }
        }

        /// <summary>
        /// 通过文件流上传文件至指定地址
        /// </summary>
        /// <param name="byteData">文件字节数组</param>
        /// <param name="fileName">文件名</param>
        /// <param name="savepath">保存地址</param>
        /// <param name="isThumbnail">是否生成缩略图</param>
        /// <param name="isWater">是否打水印</param>
        /// <returns>上传成功返回JSON字符串</returns>
        public string FileSaveAs(byte[] byteData, string fileName, string savepath, bool isThumbnail, bool isWater)
        {
            try
            {
                string fileExt = Path.GetExtension(fileName).Trim('.'); //文件扩展名，不含“.”
                string newFileName = Utils.GetRamCode() + "." + fileExt; //随机生成新的文件名
                string newThumbnailFileName = "thumb_" + newFileName; //随机生成缩略图文件名

                string upLoadPath = savepath; //本地上传目录相对路径
                string fullUpLoadPath = Utils.GetMapPath(upLoadPath); //本地上传目录的物理路径
                string newFilePath = upLoadPath + newFileName; //本地上传后的路径
                string newThumbnailPath = upLoadPath + newThumbnailFileName; //本地上传后的缩略图路径

                byte[] thumbData = null; //缩略图文件流

                //检查文件字节数组是否为NULL
                if (byteData == null)
                {
                    return "{\"status\": 0, \"msg\": \"请选择要上传的文件！\"}";
                }
                //检查文件扩展名是否合法
                if (!CheckFileExt(fileExt))
                {
                    return "{\"status\": 0, \"msg\": \"不允许上传" + fileExt + "类型的文件！\"}";
                }
                //检查文件大小是否合法
                if (!CheckFileSize(fileExt, byteData.Length))
                {
                    return "{\"status\": 0, \"msg\": \"文件超过限制的大小！\"}";
                }
                //如果是图片，检查是否需要生成缩略图，是则裁剪生成300*300长度
                if (IsImage(fileExt) && isThumbnail)
                {
                    thumbData = Thumbnail.MakeThumbnailImage(byteData, fileExt, 300, 300, "Cut");
                }
                else
                {
                    newThumbnailPath = newFilePath; //不生成缩略图则返回原图
                }
                //检查本地上传的物理路径是否存在，不存在则创建
                if (!Directory.Exists(fullUpLoadPath))
                {
                    Directory.CreateDirectory(fullUpLoadPath);
                }
                //保存主文件
                FileHelper.SaveFile(byteData, fullUpLoadPath + newFileName);
                //保存缩略图文件
                if (thumbData != null)
                {
                    FileHelper.SaveFile(thumbData, fullUpLoadPath + newThumbnailFileName);
                }
                //处理完毕，返回JOSN格式的文件信息
                return "{\"status\": 1, \"msg\": \"上传文件成功！\", \"name\": \""
                    + fileName + "\", \"path\": \"" + newFilePath + "\", \"thumb\": \""
                    + newThumbnailPath + "\", \"size\": " + byteData.Length + ", \"ext\": \"" + fileExt + "\"}";
            }
            catch
            {
                return "{\"status\": 0, \"msg\": \"上传过程中发生意外错误！\"}";
            }
        }

        /// <summary>
        /// 文件上传方法
        /// </summary>
        /// <param name="postedFile">文件流</param>
        /// <param name="isThumbnail">是否生成缩略图</param>
        /// <param name="isWater">是否打水印</param>
        /// <returns>上传后文件信息</returns>
        public string fileSaveAs(HttpPostedFile postedFile, bool isThumbnail, bool isWater)
        {
            try
            {
                string fileExt = Path.GetExtension(postedFile.FileName).Trim('.'); //文件扩展名，不含“.”
                int fileSize = postedFile.ContentLength; //获得文件大小，以字节为单位
                string fileName = postedFile.FileName.Substring(postedFile.FileName.LastIndexOf(@"\") + 1); //取得原文件名
                string newFileName = Utils.GetRamCode() + "." + fileExt; //随机生成新的文件名
                string newThumbnailFileName = "thumb_" + newFileName; //随机生成缩略图文件名
                string upLoadPath = GetUpLoadPath(); //上传目录相对路径
                string fullUpLoadPath = Utils.GetMapPath(upLoadPath); //上传目录的物理路径
                string newFilePath = upLoadPath + newFileName; //上传后的路径
                string newThumbnailPath = upLoadPath + newThumbnailFileName; //上传后的缩略图路径

                //检查文件扩展名是否合法
                if (!CheckFileExt(fileExt))
                {
                    return "{\"status\": 0, \"temp\": \"不允许上传" + fileExt + "类型的文件！\"}";
                }
                //检查文件大小是否合法
                if (!CheckFileSize(fileExt, fileSize))
                {
                    return "{\"status\": 0, \"temp\": \"文件超过限制的大小！\"}";
                }
                //检查上传的物理路径是否存在，不存在则创建
                if (!Directory.Exists(fullUpLoadPath))
                {
                    Directory.CreateDirectory(fullUpLoadPath);
                }

                //保存文件
                postedFile.SaveAs(fullUpLoadPath + newFileName);

                //处理完毕，返回JOSN格式的文件信息
                return "{\"status\": 1, \"temp\": \"上传文件成功！\", \"name\": \""
                    + fileName + "\", \"path\": \"" + newFilePath + "\", \"thumb\": \""
                    + newThumbnailPath + "\", \"size\": " + fileSize + ", \"ext\": \"" + fileExt + "\"}";
            }
            catch
            {
                return "{\"status\": 0, \"temp\": \"上传过程中发生意外错误！\"}";
            }
        }


        /// <summary>
        /// 删除上传文件
        /// </summary>
        /// <param name="fileUri">相对地址或网址</param>
        public void DeleteFile(string fileUri)
        {
            //文件不应是上传文件，防止跨目录删除
            if (fileUri.IndexOf("..") == -1 && fileUri.ToLower().StartsWith("/upload"))
            {
                FileHelper.DeleteUpFile(fileUri);
            }
        }

        #region 私有方法
        /// <summary>
        /// 返回上传目录相对路径
        /// </summary>
        /// <param name="fileName">上传文件名</param>
        private string GetUpLoadPath()
        {
            string path = "/upload/"; //站点目录+上传目录
            //按年月日每天一个文件夹
            path += DateTime.Now.ToString("yyyyMMdd");
            return path + "/";
        }

        /// <summary>
        /// 是否为图片文件
        /// </summary>
        /// <param name="_fileExt">文件扩展名，不含“.”</param>
        private bool IsImage(string _fileExt)
        {
            ArrayList al = new ArrayList();
            al.Add("bmp");
            al.Add("jpeg");
            al.Add("jpg");
            al.Add("gif");
            al.Add("png");
            if (al.Contains(_fileExt.ToLower()))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 检查是否为合法的上传文件
        /// </summary>
        public bool CheckFileExt(string _fileExt)
        {
            //检查危险文件
            string[] excExt = { "asp", "aspx", "ashx", "asa", "asmx", "asax", "php", "jsp", "htm", "html" };
            for (int i = 0; i < excExt.Length; i++)
            {
                if (excExt[i].ToLower() == _fileExt.ToLower())
                {
                    return false;
                }
            }
            //检查合法文件
            string[] allowExt = ("gif,jpg,jpeg,png,bmp,xls,xlsx,wav,aif,aiff,au,mp3,ram,ra,rm,mid,rmi").Split(',');
            for (int i = 0; i < allowExt.Length; i++)
            {
                if (allowExt[i].ToLower() == _fileExt.ToLower())
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 检查文件大小是否合法
        /// </summary>
        /// <param name="_fileExt">文件扩展名，不含“.”</param>
        /// <param name="_fileSize">文件大小(B)</param>
        private bool CheckFileSize(string _fileExt, int _fileSize)
        {
            //判断是否为图片文件
            if (IsImage(_fileExt))
            {
                if (_fileSize > 10240 * 1024)//不能大于10M
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 检查文件地址是否文件服务器地址
        /// </summary>
        /// <param name="url">文件地址</param>
        private static bool IsExternalIPAddress(string url)
        {
            if (!string.IsNullOrEmpty(url))
            {
                var uri = new Uri(url);
                switch (uri.HostNameType)
                {
                    case UriHostNameType.Dns:
                        var ipHostEntry = Dns.GetHostEntry(uri.DnsSafeHost);
                        foreach (IPAddress ipAddress in ipHostEntry.AddressList)
                        {
                            byte[] ipBytes = ipAddress.GetAddressBytes();
                            if (ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                            {
                                if (!IsPrivateIP(ipAddress))
                                {
                                    return true;
                                }
                            }
                        }
                        break;

                    case UriHostNameType.IPv4:
                        return !IsPrivateIP(IPAddress.Parse(uri.DnsSafeHost));
                }
            }
            return false;
        }

        /// <summary>
        /// 检查IP地址是否本地服务器地址
        /// </summary>
        /// <param name="myIPAddress">IP地址</param>
        private static bool IsPrivateIP(IPAddress myIPAddress)
        {
            if (IPAddress.IsLoopback(myIPAddress)) return true;
            if (myIPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            {
                byte[] ipBytes = myIPAddress.GetAddressBytes();
                // 10.0.0.0/24 
                if (ipBytes[0] == 10)
                {
                    return true;
                }
                // 172.16.0.0/16
                else if (ipBytes[0] == 172 && ipBytes[1] == 16)
                {
                    return true;
                }
                // 192.168.0.0/16
                else if (ipBytes[0] == 192 && ipBytes[1] == 168)
                {
                    return true;
                }
                // 169.254.0.0/16
                else if (ipBytes[0] == 169 && ipBytes[1] == 254)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="path">文件名称</param>
        /// <param name="local">本地路径</param>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        public static string UpLoadFile(string Url, string FilePath, string fileName, byte[] bytes)
        {
            try
            {
                //检查Url文件地址是否文件服务器地址
                if (IsExternalIPAddress(Url))
                {
                    #region 上传到文件服务器
                    if (bytes.Length == 0)
                    {
                        return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = "请选择传需要上传的文件" });
                    }
                    Dictionary<string, dynamic> keyValues = new Dictionary<string, dynamic>();
                    keyValues.Add("FilePath", FilePath); //本地上传目录相对路
                    string result = UpLoad.FromUploadFilePostAsync(Url + "/Api/IUploadFile/UploadFile", keyValues, bytes:bytes,fileName: fileName);
                    if (!string.IsNullOrEmpty(result))
                    {
                        ReturnMsgModel msgModel = JsonHelper.ToObject<ReturnMsgModel>(result);
                        if (msgModel.status)
                        {
                            return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = true, code = 200, msg = "上传成功", data = msgModel.data });
                        }
                    }
                    #endregion
                }
                else
                {
                    #region 上传到本地服务器
                    string upLoadPath = GetUpLoadPath(FilePath); //本地上传目录相对路径
                    string fullUpLoadPath = Utils.GetMapPath(upLoadPath); //上传目录的物理路径
                    string newFilePath = fullUpLoadPath + fileName; //上传后的路径

                    //检查上传的物理路径文件夹是否存在，不存在则创建
                    if (!Directory.Exists(fullUpLoadPath))
                    {
                        Directory.CreateDirectory(fullUpLoadPath);
                    }

                    //保存主文件
                    bool result = FileHelper.SaveFile(bytes, newFilePath);
                    if (result)
                    {
                        string VoiceFile = upLoadPath + fileName;

                        #region 文件格式转换
                        //文件转换
                        string fileType = Common.FileHelper.GetFileExt(fileName);//文件类型
                        if (fileType != "mp3" && fileType != "wav")
                        {
                            string inputFilePath = AppDomain.CurrentDomain.BaseDirectory + VoiceFile;// 获取文件的相对路径
                            string outputFilePath = inputFilePath.Replace(string.Format(".{0}", fileType), ".mp3");
                            string results = AudioConverter.ConvertToMp3(inputFilePath, outputFilePath);
                            if (results == "true")
                            {
                                VoiceFile = outputFilePath.Replace(AppDomain.CurrentDomain.BaseDirectory, "");//去除绝对路径
                            }
                        }
                        #endregion

                        return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = true, code = 200, msg = "上传成功!", data = VoiceFile });
                    }
                    #endregion
                }
                return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = "上传失败!"});
            }
            catch (Exception ex)
            {
                return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = "上传失败!" + ex.Message });
            }
        }

        public static string GetUpLoadPath(string loader)
        {
            string path = string.Format("/upload/{0}/", loader); //站点目录+上传目录
            //按年月日每天一个文件夹
            path += DateTime.Now.ToString("yyyyMMdd");
            return path + "/";
        }

        /// 将 Stream 转成 byte[]
        public static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }
        public class ReturnMsgModel
        {
            public bool status { get; set; }
            public int code { get; set; }
            public string msg { get; set; }
            public object data { get; set; }
        }
        #endregion

        #region 上传到外网

        public static string FromUploadFilePostAsync(string url, Dictionary<string, dynamic> keyValues, HttpPostedFile file = null,byte[] bytes=null,string fileName="")
        {
            using (var client = new HttpClient())
            {
                using (var content = new MultipartFormDataContent())
                {
                    Stream fileStream = null;
                    if (file != null)
                    {
                        fileStream =  file.InputStream;
                        // 添加文件内容
                        content.Add(new StreamContent(fileStream, (int)fileStream.Length), "File", fileName);
                    }
                    // 添加byte数据作为文件流
                    if (bytes != null)
                    {
                        content.Add(new ByteArrayContent(bytes, 0, bytes.Length), "File", fileName);
                    }
                   
                    if (keyValues.Count > 0)
                    {
                        // 添加其他参数
                        foreach (var item in keyValues)
                        {
                            content.Add(new StringContent(item.Value), item.Key);
                        }
                    }

                    try
                    {
                        var response = client.PostAsync(url, content).Result;

                        if (response.IsSuccessStatusCode)
                        {
                            var jsonString = response.Content.ReadAsStringAsync().Result;
                            jsonString = jsonString.Replace("\\", "");
                            jsonString = jsonString.Replace("\"{", "{");
                            jsonString = jsonString.Replace("}\"", "}");
                            return jsonString;//返回操作结果
                        }
                        else
                        {
                            return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = "上传失败" });
                        }
                    }
                    catch (Exception ex)
                    {
                        return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = ex.Message });
                    }
                    finally
                    {
                        //关闭文件流
                        if (fileStream != null)
                        {
                            fileStream.Close();
                        }
                        client.Dispose();
                    }
                }
            }
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="path">文件名称</param>
        /// <param name="local">本地路径</param>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        public static string PostUpLoadFile(string FilePath, string fileName, byte[] bytes)
        {
            try
            {
                string upLoadPath = GetUpLoadPath(FilePath); //本地上传目录相对路径
                string fullUpLoadPath = Utils.GetMapPath(upLoadPath); //上传目录的物理路径
                string newFilePath = fullUpLoadPath + fileName; //上传后的路径

                //检查上传的物理路径文件夹是否存在，不存在则创建
                if (!Directory.Exists(fullUpLoadPath))
                {
                    Directory.CreateDirectory(fullUpLoadPath);
                }

                //保存主文件
                bool result = FileHelper.SaveFile(bytes, newFilePath);
                if (result)
                {
                    var fileModel = new FileModel()
                    {
                        FileName = fileName,
                        FilePath = upLoadPath + fileName,
                        FileSize = bytes.LongLength.ToString(),
                        FileExt = "."+Common.FileHelper.GetFileExt(fileName),//文件类型
                    };
                    return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = true, code = 200, msg = "上传成功!", data = fileModel });
                }
                return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = "上传失败!" });
            }
            catch (Exception ex)
            {
                return JsonHelper.ObjectToJSON(new ReturnMsgModel { status = false, code = 400, msg = "上传失败!" + ex.Message });
            }
        }
        public class FileModel
        {
            /// <summary>
            /// 文件名称
            /// </summary>
            public string FileName { get; set; }
            /// <summary>
            /// 文件路径
            /// </summary>
            public string FilePath { get; set; }
            /// <summary>
            /// 文件大小
            /// </summary>
            public string FileSize { get; set; }
            /// <summary>
            /// 文件类型
            /// </summary>
            public string FileExt { get; set; }
        }
        #endregion
    }
}
